local function newDashMode(player)
	local mo = player.mo

	if (player.charflags & SF_DASHMODE)
		if (player.newdash == nil)
			player.newdash = 0
		end

		local THRESHOLD = DASHMODE_THRESHOLD
		local MAX = THRESHOLD + (5*TICRATE)

		local totallyradical = 1
		local runspeed = FixedMul(player.runspeed, mo.scale)

		if (player.speed >= runspeed)
			totallyradical = 2
		elseif (player.speed < runspeed/2) and (P_IsObjectOnGround(mo))
			totallyradical = 0 -- Only remove dash mode when below a certain speed on the ground
		end

		if (player.gotflag)
		or (player.exiting)
		or (maptol & TOL_NIGHTS)
		or (P_PlayerInPain(player))
			totallyradical = 0
		else
			if (player.pflags & PF_SPINNING)
				totallyradical = max($1, 1)
			end

			if (player.pflags & PF_STARTDASH)
				totallyradical = 2
			end

			if ((player.powers[pw_carry] == CR_GENERIC)
			or (player.powers[pw_carry] == CR_PLAYER)
			or (player.powers[pw_carry] == CR_MACESPIN)
			or (player.powers[pw_carry] == CR_ROPEHANG)
			or (player.powers[pw_carry] == CR_MINECART)
			or (player.powers[pw_carry] == CR_ROLLOUT)
			or (player.powers[pw_carry] == CR_ZOOMTUBE)
			or (player.powers[pw_justsprung])) -- Keep dash mode through these gimmicks
			or (player.secondjump == 1) -- Keep but don't increase while floating
				totallyradical = 1
			end
		end

		if (totallyradical == 2)
			if (player.newdash < MAX)
				local playsnd = (player.newdash < THRESHOLD)

				if (player.newdash < THRESHOLD)
				and ((player.speed > 60*mo.scale) or (player.dashspeed > 60*FRACUNIT))
					player.newdash = THRESHOLD -- Above the speed limit, you should just have dash mode now
				else
					player.newdash = $1+1
				end

				if (playsnd and player.newdash >= THRESHOLD)
					if (player.charflags & SF_MACHINE)
						S_StartSound(mo, sfx_kc4d)
					else
						S_StartSound(mo, sfx_cdfm40)
					end
				end
			end
		elseif (totallyradical == 0)
			if (player.newdash >= THRESHOLD)
				S_StartSound(mo, sfx_kc65)
			end

			player.newdash = 0
		end

		if (player.newdash < THRESHOLD)
			player.normalspeed = skins[mo.skin].normalspeed
			player.jumpfactor = skins[mo.skin].jumpfactor
		else
			local timetomax = MAX - THRESHOLD
			local amt = player.newdash - THRESHOLD

			if (player.normalspeed < 2 * skins[mo.skin].normalspeed)
				local a = player.normalspeed / timetomax
				player.normalspeed = skins[mo.skin].normalspeed + (a * amt)
			end

			if (player.jumpfactor < (5 * skins[mo.skin].jumpfactor) / 4)
				local a = (skins[mo.skin].jumpfactor / 4) / timetomax
				player.jumpfactor = skins[mo.skin].jumpfactor + (a * amt)
			end
		end

		if (player.newdash >= THRESHOLD)
			player.dashmode = DASHMODE_MAX
		else
			player.dashmode = player.newdash
		end
	else
		player.newdash = nil
	end
end

local function metalHover(player)
	local mo = player.mo
	
	if ((player.charflags & SF_DASHMODE) and (player.dashmode >= DASHMODE_THRESHOLD))
		mo.state = S_PLAY_DASH
	elseif (player.speed >= FixedMul(player.runspeed, mo.scale))
		mo.state = S_PLAY_FLOAT_RUN
	else
		mo.state = S_PLAY_FLOAT
	end

	player.pflags = ($1|PF_THOKKED) & ~(PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING)
	player.secondjump = 1

	mo.momz = 0
end

addHook("AbilitySpecial", function(player)
	if not mapheaderinfo[gamemap].azlantruin then return end
	if not (player.mo and player.mo.valid)
		return
	end

	local mo = player.mo

	if (mo.skin == "metalsonic")
	and (player.charability == CA_FLOAT)
		if ((player.charflags & SF_MULTIABILITY) or not (player.pflags & PF_THOKKED))
			player.charflags = (SF_MACHINE|SF_DASHMODE)
			player.metalhovertime = TICRATE
			player.drawangle = mo.angle
			P_InstaThrust(mo, mo.angle, player.speed)
			S_StartSound(mo, sfx_kc3c)
			metalHover(player)
		end
		
		return true
	end
end)

addHook("PlayerThink", function(player)
	if not mapheaderinfo[gamemap].azlantruin then return end
	if not (player.mo and player.mo.valid)
		return
	end

	newDashMode(player)

	if (player.metalhovertime != nil) and (player.metalhovertime > 0)
		if (P_IsObjectOnGround(player.mo))
		or (player.powers[pw_carry])
		or (player.powers[pw_justsprung])
		or (P_PlayerInPain(player))
			player.metalhovertime = 0
		else
			player.metalhovertime = $1-1
		end

		if (player.metalhovertime <= 0)
			player.secondjump = 0
		else
			metalHover(player)
		end
	end
end)

addHook("FollowMobj", function(player, fume)
	if not mapheaderinfo[gamemap].azlantruin then return end
	if (fume.type != MT_METALJETFUME)
		-- bruh
		return
	end

	-- YAY, I get to completely recode this just to add 1 tiny bit of new behavior!
	local FUME_SKINCOLORS = {
		SKINCOLOR_ICY,
		SKINCOLOR_SKY,
		SKINCOLOR_CYAN,
		SKINCOLOR_WAVE,
		SKINCOLOR_TEAL,
		SKINCOLOR_AQUA,
		SKINCOLOR_SEAFOAM,
		SKINCOLOR_MINT,
		SKINCOLOR_PERIDOT,
		SKINCOLOR_LIME,
		SKINCOLOR_YELLOW,
		SKINCOLOR_SANDY,
		SKINCOLOR_GOLD,
		SKINCOLOR_APRICOT,
		SKINCOLOR_SUNSET
	}

	local mo = player.mo
	local angle = player.drawangle
	local panim = player.panim
	local dashmode = player.dashmode
	local underwater = (mo.eflags & MFE_UNDERWATER)
	local stat = fume.state

	local floatscale = 0
	if (player.metalhovertime != nil)
		floatscale = (mo.scale * player.metalhovertime) / TICRATE -- the only difference
	end

	if (panim != PA_WALK and panim != PA_RUN and panim != PA_DASH and not floatscale)
		if (stat != fume.info.spawnstate)
			fume.state = fume.info.spawnstate
		end

		return true
	end

	if (underwater)
		fume.movedir = FixedAngle(FixedDiv(2 * player.speed, 3 * mo.scale))
		fume.movefactor = $1 + player.speed

		if (fume.movefactor > FixedDiv(2 * player.normalspeed, 3 * mo.scale))
			local shift = 0
			if (panim == PA_WALK and not floatscale)
				shift = 1
			end

			local radiusV = 4*FRACUNIT
			local radiusX = P_ReturnThrustX(mo, angle, -mo.radius >> shift)
			local radiusY = P_ReturnThrustY(mo, angle, -mo.radius >> shift)
			local factorX = P_ReturnThrustX(mo, angle + ANGLE_90, mo.scale)
			local factorY = P_ReturnThrustY(mo, angle + ANGLE_90, mo.scale)

			local i = -1
			while (i < 2)
				local offsetH = i*P_ReturnThrustX(fume, fume.movedir, radiusV)
				local offsetV = i*P_ReturnThrustY(fume, fume.movedir, radiusV)
				local x = mo.x + radiusX + FixedMul(offsetH, factorX)
				local y = mo.y + radiusY + FixedMul(offsetH, factorY)
				local z = mo.z + (mo.height >> 1) + offsetV
				local bubble = P_SpawnMobj(x, y, z, MT_SMALLBUBBLE)
				P_SetScale(bubble, (mo.scale + floatscale) >> 1)
				i = $1+2
			end

			fume.movefactor = 0
		end

		if (panim == PA_WALK and not floatscale)
			if (stat != fume.info.spawnstate)
				fume.threshold = 0
				fume.state = fume.info.spawnstate
			end

			return true
		end
	end

	if (stat == fume.info.spawnstate)
		fume.state = fume.info.seestate
		stat = fume.info.seestate
		P_SetScale(fume, mo.scale)
	end

	if (dashmode > DASHMODE_THRESHOLD and stat != fume.info.seestate)
		fume.destscale = mo.scale + (floatscale << 1) -- there it is, the one difference
		fume.flags2 = $1 ^^ MF2_DONTDRAW
		fume.flags2 = $1|(mo.flags2 & MF2_DONTDRAW)
	else
		if (dashmode == DASHMODE_THRESHOLD and dashmode > fume.movecount)
			fume.state = fume.info.seestate
			stat = fume.info.seestate
			P_SetScale(fume, mo.scale << 1)
		end

		fume.flags2 = ($1 & ~MF2_DONTDRAW) | (mo.flags2 & MF2_DONTDRAW)
		fume.destscale = mo.scale + FixedDiv(player.speed, player.normalspeed)

		if (underwater)
			fume.destscale = $1 / 6
		else
			fume.destscale = $1 / 3
		end

		fume.destscale = $1 + floatscale -- there it is, the one difference
		fume.color = FUME_SKINCOLORS[((dashmode * #FUME_SKINCOLORS) / (DASHMODE_MAX + 1)) + 1]

		if (underwater)
			fume.frame = ($1 & FF_FRAMEMASK) | FF_ANIMATE | (P_RandomRange(0, 9) * FF_TRANS10)
			fume.threshold = 1
		elseif (fume.threshold)
			fume.frame = ($1 & FF_FRAMEMASK) | states[fume.state].frame
			fume.threshold = 0
		end
	end

	if (player.metalhovertime != nil)
		if (player.metalhovertime > fume.extravalue1)
			-- Set instantly when you first hover
			P_SetScale(fume, fume.destscale)
		end

		fume.extravalue1 = player.metalhovertime
	end

	fume.movecount = dashmode
	fume.flags2 = ($1 & ~MF2_OBJECTFLIP) | (mo.flags2 & MF2_OBJECTFLIP)
	fume.eflags = ($1 & ~MFE_VERTICALFLIP) | (mo.eflags & MFE_VERTICALFLIP)

	local dist = -mo.radius - FixedMul(fume.info.radius, fume.destscale - mo.scale/3)

	P_TeleportMove(fume, 
		mo.x + P_ReturnThrustX(fume, angle, dist),
		mo.y + P_ReturnThrustY(fume, angle, dist),
		mo.z + ((mo.height - fume.height) >> 1)
	)

	return true
end) --MT_METALJETFUME -- apparently you can't set the mobj type here?!?!
